package com.leyou.user.service;

import com.leyou.common.auth.entity.Payload;
import com.leyou.common.auth.entity.UserInfo;
import com.leyou.common.auth.utils.JwtUtils;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exceptions.LyException;
import com.leyou.common.threadlocals.UserHolder;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.CookieUtils;
import com.leyou.common.utils.RegexUtils;
import com.leyou.user.dto.AddressDTO;
import com.leyou.user.dto.UserDTO;
import com.leyou.user.entity.Address;
import com.leyou.user.entity.User;
import com.leyou.user.mapper.AddressMapper;
import com.leyou.user.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.weaver.ast.Var;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.support.RequestContext;

import javax.servlet.http.HttpServletRequest;

import static com.leyou.common.constants.MQConstants.Exchange.*;
import static com.leyou.common.constants.MQConstants.RoutingKey.*;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @package com.leyou.user.service
 * @description:
 * @author: 许超越
 * @date 2019/7/6 17:08
 * @version: V1.0
 */
@Service
@Slf4j
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private static final String KEY_PREFIX = "verity:code:phone";

    @Autowired
    private AmqpTemplate amqpTemplate;

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    @Autowired
    private AddressMapper addressMapper;

    private static final String COOKIE_NAME = "LY_TOKEN";

    /**
     * 校验数据是否可用
     *
     * @param data
     * @param type
     * @return
     */
    public Boolean checkUserData(String data, Integer type) {
        User user = new User();
        switch (type) {
            //类型为用户名
            case 1:
                user.setUsername(data);
                break;
            //类型为手机号码
            case 2:
                user.setPhone(data);
                break;
            //传递的参数有问题
            default:
                throw new LyException(ExceptionEnum.INVALID_PARAM_ERROR);
        }
        //返回结果
        return userMapper.selectCount(user) == 0;
    }


    /**
     * 发送短信验证码
     * @param phone 手机号码
     */
    public void sendCode(String phone) {
        //验证手机号码是够合规
        if (!RegexUtils.isPhone(phone)) {
            throw new LyException(ExceptionEnum.INVALID_PHONE_NUMBER);
        }
        //生成一个随机验证码
        String code = RandomStringUtils.randomNumeric(6);
        //将验证码存入Redis中，让其生命周期只有5分钟与业务需求保持一致
        redisTemplate.opsForValue().set(KEY_PREFIX + phone, code, 5, TimeUnit.MINUTES);
        //发送短信，将验证码发送到用户手机
        Map<String, String> msg = new HashMap<>();
        msg.put("phone", phone);
        msg.put("code", code);
        amqpTemplate.convertAndSend(SMS_EXCHANGE_NAME, VERIFY_CODE_KEY, msg);
    }


    /**
     * 注册用户
     * @param user 用户信息
     * @param code 验证码
     */
    public void register(User user, String code) {
        //获取验证码
        String cacheCode = redisTemplate.opsForValue().get(KEY_PREFIX + user.getPhone());
        //校验验证码
        if (!StringUtils.equals(code, cacheCode)) {
            throw new LyException(ExceptionEnum.INVALID_VERIFY_CODE);
        }
        //对密码进行加密
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        //将用户存入数据并对结果进行判定
        if (userMapper.insertSelective(user) != 1) {
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }
    }


    /**
     * 根据用户名和密码查询用户
     * @param username
     * @param password
     * @return
     */
    public UserDTO queryUserByUsernameAndPassword(String username, String password) {
        //根据用户名查询用户
        User record = new User();
        record.setUsername(username);
        User user = userMapper.selectOne(record);
        //判断user是否存在
        if (user == null) {
            throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
        }
        //对数据库中的密码和客户输入的密码进行匹配
        if (!passwordEncoder.matches(password, user.getPassword())) {
            throw new LyException(ExceptionEnum.INVALID_USERNAME_PASSWORD);
        }
        return BeanHelper.copyProperties(user, UserDTO.class);
    }


    /**
     * 查询当前登入用户的收件地址
     * @return
     */
    public List<AddressDTO> queryAddress(HttpServletRequest request) {
        Long userId = null;
        try {
            //获取当前强求的cookie
            String token = CookieUtils.getCookieValue(request, COOKIE_NAME);
            //解析token
            Payload<UserInfo> payload = JwtUtils.getInfoFromToken(token, UserInfo.class);
            //获取用户信息
            userId = payload.getUserInfo().getId();
        } catch (UnsupportedEncodingException e) {
            log.error("【购物车服务】解析用户信息失败！", e);
            throw new RuntimeException(e);
        }
        //根据id查询查询收件地址
        Address address = new Address();
        address.setUserId(userId);
        List<Address> addressList = addressMapper.select(address);
        //返回查询结果
        return BeanHelper.copyWithCollection(addressList, AddressDTO.class);
    }


    /**
     * 根据用户id和地址id查询查询地址
     * @param id
     * @param userId
     * @return
     */
    public AddressDTO queryAddressByUserIdAndId(Long id, Long userId) {
        //创建查询对象
        Address address = new Address();
        address.setId(id);
        address.setUserId(userId);
        //返回执行查询
        return BeanHelper.copyProperties(addressMapper.selectOne(address), AddressDTO.class);
    }
}
